package qnb.service.impl;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import qnb._common.easyui.MenuVO;
import qnb._common.easyui.Tree;
import qnb.dao.SysPowerMapper;
import qnb.dao.SysPowerStudentMapper;
import qnb.dao.SysPowerTeacherMapper;
import qnb.dao.SysRoleMapper;
import qnb.entity.*;
import qnb.service.SysPowerService;

import javax.servlet.http.HttpSession;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author huangxin
 * @date 2019/5/20-10:15
 */
@Service("sysPowerService")
public class SysPowerServiceImpl implements SysPowerService {
    private static Logger log = Logger.getLogger(SysPowerServiceImpl.class);

    @Autowired
    private SysPowerMapper sysPowerMapper;

    @Autowired
    private SysRoleMapper sysRoleMapper;

    @Autowired
    private SysPowerTeacherMapper sysPowerTeacherMapper;

    @Autowired
    private SysPowerStudentMapper sysPowerStudentMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;


    public static final String POWER_CODE = "powerCode:";
    public static final String STUDENT = "student:";
    public static final String TEACHER = "teacher:";
    public static final String MENU = "menu:";
    public static final String ALL_POWER = "allPower";


    /**
     * 获取老师的权限代码
     *
     * @return
     */
    @Override
    public List<SysPower> getPowersByTeacherId(String id) {
        SysPowerTeacher sysPowerTeacher = sysPowerTeacherMapper.selectByPrimaryKey(id);
        if (sysPowerTeacher == null) {
            return null;
        }

        Set<String> set = new HashSet<>();

        //直接权限
        String powerStr = sysPowerTeacher.getSysPowers();

        if (StringUtils.isNotBlank(powerStr)) {
            String[] powerArr = powerStr.split(",");
            //直接权限存入set去除重复
            Arrays.stream(powerArr).forEach(s -> set.add(s));
        }

        //角色数组
        String roles = sysPowerTeacher.getSysRole();
        //角色不为空
        if (StringUtils.isNotBlank(roles)) {
            String[] roleIds = roles.split(",");
            //获取角色的所有权限id
            List<String> powers = sysRoleMapper.findPowerByRoleIds(roleIds);
            powers.forEach(p -> {
                //如果权限id不为空
                if (StringUtils.isNotBlank(p)) {
                    //分割权限id字符串
                    String[] split = p.split(",");
                    //添加进set去除重复
                    Arrays.stream(split).forEach(s -> set.add(s));
                }
            });
        }

        if (set.size() > 0) {
            //获取权限集合
            List<SysPower> powerList = sysPowerMapper.findPowerCodeByIds(set.toArray(new String[set.size()]));
            return powerList;
        }

        return null;
    }

    /**
     * 获取学生的权限代码
     *
     * @param id
     * @return
     */
    @Override
    public List<SysPower> getPowersByStudentId(String id) {
        SysPowerStudent sysPowerStudent = sysPowerStudentMapper.selectByPrimaryKey(id);

        if (sysPowerStudent == null) {
            return null;
        }

        Set<String> set = new HashSet<>();

        //直接权限
        String powerStr = sysPowerStudent.getSysPowers();

        if (StringUtils.isNotBlank(powerStr)) {
            String[] powerArr = powerStr.split(",");
            //直接权限存入set去除重复
            Arrays.stream(powerArr).forEach(s -> set.add(s));
        }

        //角色数组
        String roles = sysPowerStudent.getSysRole();
        //角色不为空
        if (StringUtils.isNotBlank(roles)) {
            String[] roleIds = roles.split(",");
            //获取角色的所有权限id
            List<String> powers = sysRoleMapper.findPowerByRoleIds(roleIds);
            powers.forEach(p -> {
                //如果权限id不为空
                if (StringUtils.isNotBlank(p)) {
                    //分割权限id字符串
                    String[] split = p.split(",");
                    //添加进set去除重复
                    Arrays.stream(split).forEach(s -> set.add(s));
                }
            });
        }

        if (set.size() > 0) {
            //获取权限集合
            List<SysPower> powerList = sysPowerMapper.findPowerCodeByIds(set.toArray(new String[set.size()]));
            return powerList;
        }

        return null;
    }


    /**
     * 根据角色id获取权限
     */
    /**
     * 根据角色id读取权限
     *
     * @param roleId
     * @return
     */
    @Override
    public List<Tree> getPowerByRoleId(Integer roleId) {
        //判断是否为已保存的角色
        if (roleId < 0) {
            return null;
        }
        //初始化
        if (roleId == 0) {
            return getAllPower(null);
        }

        SysRole sysRole = sysRoleMapper.selectByPrimaryKey(roleId);
        if (sysRole == null) {
            throw new RuntimeException("角色不存在");
        }

        List<Tree> treeList = getAllPower(sysRole.getSysRoleLevel());


        //获取角色所带的权限id
        if (sysRole.getSysRolePowers() != null) {
            String[] powerIds = StringUtils.split(sysRole.getSysRolePowers(), ",");
            List<Integer> idList = Arrays.stream(powerIds).map(Integer::parseInt).collect(Collectors.toList());

            setCheck(treeList, idList);
        }
        return treeList;
    }

    /**
     * 根据老师id获取权限转换成tree
     *
     * @param id
     * @return
     */
    @Override
    public List<Tree> getPowerByTeacherId(String id) {
        if ("0".equals(id)) {
            return getAllPower(null);
        }
        //老师可获得的权限等级为1
        List<Tree> treeList = getAllPower(1);
        SysPowerTeacher sysPowerTeacher = sysPowerTeacherMapper.selectByPrimaryKey(id);

        if (sysPowerTeacher != null) {
            //如果存在直接权限
            String sysPowers = sysPowerTeacher.getSysPowers();
            if (StringUtils.isNotBlank(sysPowers)) {
                List<Integer> idList = Arrays.stream(StringUtils.split(sysPowers, ",")).map(Integer::parseInt).collect(Collectors.toList());
                setCheck(treeList, idList);
            }
        }
        return treeList;
    }

    /**
     * 根据学生id读取权限转换成tree
     *
     * @param id
     * @return
     */
    @Override
    public List<Tree> getPowerByStudentId(String id) {
        if ("0".equals(id)) {
            return getAllPower(null);
        }

        //学生可获得的权限等级为0
        List<Tree> treeList = getAllPower(0);
        SysPowerStudent sysPowerStudent = sysPowerStudentMapper.selectByPrimaryKey(id);

        if (sysPowerStudent != null) {
            //如果存在直接权限
            String sysPowers = sysPowerStudent.getSysPowers();
            if (StringUtils.isNotBlank(sysPowers)) {
                List<Integer> idList = Arrays.stream(StringUtils.split(sysPowers, ",")).map(Integer::parseInt).collect(Collectors.toList());
                setCheck(treeList, idList);
            }
        }
        return treeList;
    }

    /**
     * 更新老师直接权限
     *
     * @param id
     * @param ids
     * @return
     */
    @Override
    public int updateTeacherPower(String id, List<Integer> ids) {

        SysPowerTeacher sysPowerTeacher = sysPowerTeacherMapper.selectByPrimaryKey(id);
        String idsStr = ids.stream().map(String::valueOf).collect(Collectors.joining(","));
        if (sysPowerTeacher != null) {
            //如果存在
            //更新
            sysPowerTeacher.setSysPowers(idsStr);
            return sysPowerTeacherMapper.updateByPrimaryKeySelective(sysPowerTeacher);
        } else {
            //新增
            sysPowerTeacher = new SysPowerTeacher();
            sysPowerTeacher.setTeacherId(id);
            sysPowerTeacher.setSysPowers(idsStr);
            return sysPowerTeacherMapper.insertSelective(sysPowerTeacher);
        }
    }

    /**
     * 更新学生角色权限
     *
     * @param id
     * @param ids
     * @return
     */
    @Override
    public int updateStudentPower(String id, List<Integer> ids) {

        SysPowerStudent sysPowerStudent = sysPowerStudentMapper.selectByPrimaryKey(id);
        String idsStr = ids.stream().map(String::valueOf).collect(Collectors.joining(","));
        if (sysPowerStudent != null) {
            //如果存在
            //更新
            sysPowerStudent.setSysPowers(idsStr);
            return sysPowerStudentMapper.updateByPrimaryKeySelective(sysPowerStudent);
        } else {
            //新增
            sysPowerStudent = new SysPowerStudent();
            sysPowerStudent.setStudentId(id);
            sysPowerStudent.setSysPowers(idsStr);
            return sysPowerStudentMapper.insertSelective(sysPowerStudent);
        }
    }


    /**
     * 设置是否选中
     *
     * @param treeList
     * @param idList
     */
    public void setCheck(List<Tree> treeList, List<Integer> idList) {
        treeList.forEach(tree -> {
            if (idList.contains(tree.getId())) {
                tree.setChecked(true);
            }
            if (!CollectionUtils.isEmpty(tree.getChildren())) {
                setCheck(tree.getChildren(), idList);
            }
        });
    }

    /**
     * 根据用户权限返回菜单
     *
     * @param session
     * @return
     */
    @Override
    public List<MenuVO> findMenuByUser(HttpSession session) {
        Object user = session.getAttribute("loginUser");

        if (user != null) {

            //用户所拥有的权限
            List<SysPower> sysPowers = null;

            String key = null;

            //判断为老师或学生
            if (user instanceof Teacher) {
                Teacher teacher = (Teacher) user;
                key = MENU + TEACHER + teacher.getTeacherId();
                Object obj = redisTemplate.opsForValue().get(key);
                if (obj != null) {
                    log.info("从缓存里获取菜单");
                    return (List<MenuVO>) obj;
                }
                sysPowers = getPowersByTeacherId(teacher.getTeacherId());
            } else if (user instanceof Student) {
                Student student = (Student) user;
                key = MENU + STUDENT + student.getStudentId();
                Object obj = redisTemplate.opsForValue().get(key);
                if (obj != null) {
                    log.info("从缓存里获取菜单");
                    return (List<MenuVO>) obj;
                }

                sysPowers = getPowersByStudentId(((Student) user).getStudentId());
            } else {
                return null;
            }

            //所有菜单
            List<MenuVO> allMenus = findMenu();
            //用户拥有的菜单
            List<MenuVO> menus = new ArrayList<>();

            //设置菜单
            setMenu(menus, allMenus, sysPowers);

            if (menus.size() > 0) {
                log.info("菜单存入redis");
                redisTemplate.opsForValue().set(key, menus);
                return menus;
            }
        }
        return null;
    }


    @Override
    public List<String> getCodes(HttpSession session) {
        ValueOperations<String, Object> opsForValue = redisTemplate.opsForValue();

        Object user = session.getAttribute("loginUser");
        if (user != null) {
            //用户所拥有的权限代码
            List<String> codes = null;


            String key = null;
            //判断为老师或学生
            if (user instanceof Teacher) {
                Teacher teacher = (Teacher) user;
                key = POWER_CODE + TEACHER + teacher.getTeacherId();
                Object code = opsForValue.get(key);
                if (code != null) {
                    log.info("从缓存里获取权限代码");
                    return (List<String>) code;
                }
                codes = getPowersByTeacherId(teacher.getTeacherId()).stream()
                        .map(SysPower::getSysPowerCode)
                        .collect(Collectors.toList());
            } else if (user instanceof Student) {
                Student student = (Student) user;
                key = POWER_CODE + STUDENT + student.getStudentId();
                Object code = opsForValue.get(key);
                if (code != null) {
                    log.info("从缓存里获取权限代码");
                    return (List<String>) code;
                }
                codes = getPowersByStudentId(student.getStudentId()).stream()
                        .map(SysPower::getSysPowerCode)
                        .collect(Collectors.toList());
                ;
            }

            //过滤掉空字符串
            codes = codes.stream().filter(StringUtils::isNotBlank).collect(Collectors.toList());

            if (codes.size() > 0) {
                redisTemplate.opsForValue().set(key, codes);
                log.info("权限代码存入缓存");
                return codes;
            }
        }
        return null;
    }


    /**
     * 设置菜单
     *
     * @param userMenus 用户拥有的菜单
     * @param menus
     * @param sysPowers
     */
    public void setMenu(List<MenuVO> userMenus, List<MenuVO> menus, List<SysPower> sysPowers) {
        //如果有权限
        if (!CollectionUtils.isEmpty(sysPowers)) {
            for (MenuVO menu : menus) {
                //获取克隆对象,克隆的对象的children为null
                MenuVO m1 = menu.copy();
                //判断是否存在此权限
                boolean present = sysPowers.stream().filter(s -> menu.getId().equals(s.getSysPowerId())).
                        findAny().isPresent();
                if (!CollectionUtils.isEmpty(menu.getChildren())) {
                    //如果存在子节点,递归查找
                    setMenu(m1.getChildren(), menu.getChildren(), sysPowers);
                }

                //如果id正确或者子节点不为空,则添加进菜单
                if (present || !CollectionUtils.isEmpty(m1.getChildren())) {
                    userMenus.add(m1);
                }
            }
        }
    }

    /**
     * 读取菜单
     *
     * @return
     */
    @Override
    public List<MenuVO> findMenu() {
        //先查询出所有
        SysPowerExample example = new SysPowerExample();
        //条件
        example.createCriteria().andSysPowerTypeEqualTo("1");
        List<SysPower> sysPowerList = sysPowerMapper.selectByExample(example);
        //转换成menu对象
        List<MenuVO> allMenuList = sysPowerList.stream().map(this::toMenu).collect(Collectors.toList());

        return getMenuChildren(0, allMenuList);
    }


    /**
     * 获取子节点
     *
     * @param id
     * @param allList
     * @return
     */
    public List<MenuVO> getMenuChildren(Integer id, List<MenuVO> allList) {
        //查询子节点
        List<MenuVO> collect = allList.stream().filter(t -> id.equals(t.getPid())).collect(Collectors.toList());
        //如果存在
        if (collect.size() > 0) {
            //递归查询子节点
            collect.forEach(tree -> tree.setChildren(getMenuChildren(tree.getId(), allList)));
            return collect;
        } else {
            //不存在
            return null;
        }
    }


    /**
     * 获取所有权限
     *
     * @return
     */
    @Override
    public List<Tree> getAllPower(Integer level) {
        List<SysPower> sysPowerList = null;
        if (level == null) {
            sysPowerList = sysPowerMapper.selectAll();
        } else {
            SysPowerExample example = new SysPowerExample();
            example.createCriteria().andSysPowerLevelLessThanOrEqualTo(level);
            sysPowerList = sysPowerMapper.selectByExample(example);
        }
        //获取最小的id
//        List<SysPower> collect = sysPowerList.stream().sorted(Comparator.comparing(SysPower::getSysPowerId)).collect(Collectors.toList());

        //获取所有权限
        List<Tree> allPower = null;
        Object obj = redisTemplate.opsForValue().get(ALL_POWER);
        if (obj!=null){
            allPower = (List<Tree>) obj;
        }else{
            allPower = getTreeChildren(0,sysPowerMapper.selectAll());
            redisTemplate.opsForValue().set(ALL_POWER,allPower);
        }

        ArrayList<Tree> userTrees= new ArrayList<>();

        //设置树结构
        setTree(userTrees,allPower,sysPowerList);

        return userTrees;
    }




    public Tree toTree(SysPower sysPower) {
        return new Tree(sysPower.getSysPowerId(), sysPower.getSysPowerPid(), sysPower.getSysPowerName(),
                null, null, sysPower.getSysPowerUrl(), sysPower.getSysPowerCode());
    }

    public MenuVO toMenu(SysPower sysPower) {
        return new MenuVO(sysPower.getSysPowerId(), sysPower.getSysPowerPid(), sysPower.getSysPowerName(),
                null, sysPower.getSysPowerUrl());
    }

    /**
     * 设置tree子节点
     *
     * @param id
     * @param sysPowerList
     * @return
     */
    public List<Tree> getTreeChildren(Integer id, List<SysPower> sysPowerList) {
        List<Tree> childrenList = sysPowerList.stream()
                .filter(s -> id.equals(s.getSysPowerPid()))
                .map(this::toTree)
                .collect(Collectors.toList());
        //不为空
        if (!CollectionUtils.isEmpty(childrenList)) {
            //递归
            childrenList.forEach(tree -> tree.setChildren(getTreeChildren(tree.getId(), sysPowerList)));
            return childrenList;
        }

        return null;
    }

    public void setTree(List<Tree> userTrees, List<Tree> allTrees, List<SysPower> sysPowers) {
        //如果有权限
        if (!CollectionUtils.isEmpty(sysPowers)) {
            for (Tree tree : allTrees) {
                //获取克隆对象,克隆的对象的children为null
                Tree m1 = tree.copy();
                //判断是否存在此权限
                boolean present = sysPowers.stream().filter(s -> tree.getId().equals(s.getSysPowerId())).
                        findAny().isPresent();
                if (!CollectionUtils.isEmpty(tree.getChildren())) {
                    //如果存在子节点,递归查找
                    setTree(m1.getChildren(), tree.getChildren(), sysPowers);
                }

                //如果id正确或者子节点不为空,则添加进菜单
                if (present || !CollectionUtils.isEmpty(m1.getChildren())) {
                    userTrees.add(m1);
                }
            }
        }
    }
}
